//package com.cpx.config;
//
//import org.apache.logging.log4j.LogManager;
//import org.apache.logging.log4j.Logger;
//import org.springframework.dao.DataAccessException;
//import org.springframework.data.redis.connection.RedisConnection;
//import org.springframework.data.redis.core.RedisCallback;
//import org.springframework.data.redis.core.RedisTemplate;
//import org.springframework.data.redis.serializer.StringRedisSerializer;
//import org.springframework.util.CollectionUtils;
//
//import java.util.List;
//import java.util.Map;
//import java.util.Set;
//import java.util.concurrent.TimeUnit;
//
///**
// * @Auther: PanBin
// * @Date: 2018-9-20 16:26
// * @Description: redis的工具类
// * @Version: 1.0
// */
//public class RedisUtils {
//
//    private static Logger logger = LogManager.getLogger(RedisUtils.class);
//
//    private static final int DEFAULT_ACQUIRY_RESOLUTION_MILLIS = 100;
//
//    /**
//     * Lock key path.
//     */
//    private String lockKey;
//
//    /**
//     * 锁超时时间，防止线程在入锁以后，无限的执行等待
//     */
//    private int expireMsecs = 60 * 1000;
//
//    /**
//     * 锁等待时间，防止线程饥饿
//     */
//    private int timeoutMsecs = 10 * 1000;
//
//    private volatile boolean locked = false;
//
//    /**
//     * @Author: PanBin
//     * @Description: 无参构造
//     * @CreateDate: 2018-9-21 14:28
//     * @Param [redisTemplate, lockKey]
//     * @Return
//     */
//    public RedisUtils(RedisTemplate<String,Object> redisTemplate) {
//        this.redisTemplate = redisTemplate;
//    }
//
//    /**
//     * @Author: PanBin
//     * @Description: 构造函数
//     * @CreateDate: 2018-9-21 14:28
//     * @Param [redisTemplate, lockKey]
//     * @Return
//     */
//    public RedisUtils(RedisTemplate<String,Object> redisTemplate, String lockKey) {
//        this.redisTemplate = redisTemplate;
//        this.lockKey = lockKey + "_lock";
//    }
//
//    /**
//     * @Author: PanBin
//     * @Description: 构造函数，60000毫秒锁过期(等待)，防止线程饥饿
//     * @CreateDate: 2018-9-21 14:30
//     * @Param [redisTemplate, lockKey, timeoutMsecs]
//     * @Return
//     */
//    public RedisUtils(RedisTemplate<String,Object> redisTemplate, String lockKey, int timeoutMsecs) {
//        this(redisTemplate, lockKey);
//        this.timeoutMsecs = timeoutMsecs;
//    }
//
//    /**
//     * @Author: PanBin
//     * @Description: 构造函数，默认超时10000毫秒，防止线程在入锁以后，无限的执行等待；锁过期60000毫秒，防止线程饥饿。
//     * @CreateDate: 2018-9-21 14:32
//     * @Param [redisTemplate, lockKey, timeoutMsecs, expireMsecs]
//     * @Return
//     */
//    public RedisUtils(RedisTemplate<String,Object> redisTemplate, String lockKey, int timeoutMsecs, int expireMsecs) {
//        this(redisTemplate, lockKey, timeoutMsecs);
//        this.expireMsecs = expireMsecs;
//    }
//
//    private RedisTemplate<String, Object> redisTemplate;
//
//    /**
//     * @Author: PanBin
//     * @Description: 当key不存在,将key的值设为value。若给定的key已经存在，则setNX不做任何动作。
//     * @CreateDate: 2018-9-21 16:35
//     * @Param [key, value]
//     * @Return boolean
//     */
//    public boolean setNX(final String key, final String value) {
//        Object obj = null;
//        try {
//            obj = redisTemplate.execute(new RedisCallback<Object>() {
//                @Override
//                public Object doInRedis(RedisConnection connection) throws DataAccessException {
//                    StringRedisSerializer serializer = new StringRedisSerializer();
//                    Boolean success = connection.setNX(serializer.serialize(key), serializer.serialize(value));
//                    connection.close();
//                    return success;
//                }
//            });
//        } catch (Exception e) {
//            logger.error("setNX redis error, key : {}", key);
//        }
//        return obj != null ? (Boolean) obj : false;
//    }
//
//    /**
//     * @Author: PanBin
//     * @Description: 将给定key的值设为value，并返回key的旧值(old value);当key存在但不是字符串类型时,返回一个错误。
//     * @CreateDate: 2018-9-21 16:43
//     * @Param [key, value]
//     * @Return java.lang.String
//     */
//    private String getSet(final String key, final String value) {
//        Object obj = null;
//        try {
//            obj = redisTemplate.execute(new RedisCallback<Object>() {
//                @Override
//                public Object doInRedis(RedisConnection connection) throws DataAccessException {
//                    StringRedisSerializer serializer = new StringRedisSerializer();
//                    byte[] ret = connection.getSet(serializer.serialize(key), serializer.serialize(value));
//                    connection.close();
//                    return serializer.deserialize(ret);
//                }
//            });
//        } catch (Exception e) {
//            logger.error("setNX redis error, key : {}", key);
//        }
//        return obj != null ? (String) obj : null;
//    }
//
//    /**
//     * @Author: PanBin
//     * @Description: 获得lock的实现思路: 主要是使用了redis 的setnx命令,缓存了锁. reids缓存的key是锁的key,所有的共享,value是锁的到期时间(注意:这里把过期时间放在value了,没有时间上设置其超时时间) 执行过程:
//     *                    1.通过setnx尝试设置某个key的值,成功(当前没有这个锁)则返回,成功获得锁
//     *                    2.锁已经存在则获取锁的到期时间,和当前时间比较,超时的话,则设置新的值
//     * @CreateDate: 2018-9-21 14:55
//     * @Param []
//     * @Return boolean
//     */
//    public synchronized boolean lock() throws InterruptedException {
//        int timeout = timeoutMsecs;
//        while (timeout >= 0) {
//            String expiresStr = String.valueOf(System.currentTimeMillis() + expireMsecs + 1); // 锁到期时间
//            if (this.setNX(lockKey, expiresStr)) {
//                locked = true;
//                return true;
//            }
//            Object currentValueStr = this.get(lockKey); //redis里的时间
//            if (currentValueStr != null && Long.parseLong(currentValueStr.toString()) < System.currentTimeMillis()) {
//                // 判断是否为空，不为空的情况下，如果被其他线程设置了值，则第二个条件判断是过不去的
//                String oldValueStr = this.getSet(lockKey, expiresStr);// 获取上一个锁到期时间，并设置现在的锁到期时间，
//                // 只有一个线程才能获取上一个线上的设置时间，因为jedis.getSet是同步的
//                if (oldValueStr != null && oldValueStr.equals(currentValueStr)) {
//                    // 防止误删（覆盖，因为key是相同的）了他人的锁——这里达不到效果，这里值会被覆盖，但是因为什么相差了很少的时间，所以可以接受
//                    // [分布式的情况下]:如过这个时候，多个线程恰好都到了这里，但是只有一个线程的设置值和当前值相同，他才有权利获取锁
//                    // lock acquired
//                    locked = true;
//                    return true;
//                }
//            }
//            timeout -= DEFAULT_ACQUIRY_RESOLUTION_MILLIS;
//            /*
//             * 延迟100 毫秒, 这里使用随机时间可能会好一点,可以防止饥饿进程的出现,即,当同时到达多个进程,
//             * 只会有一个进程获得锁,其他的都用同样的频率进行尝试,后面有来了一些进行,也以同样的频率申请锁,这将可能导致前面来的锁得不到满足.
//             * 使用随机的等待时间可以一定程度上保证公平性
//             */
//            Thread.sleep(DEFAULT_ACQUIRY_RESOLUTION_MILLIS);
//        }
//        return false;
//    }
//
//   /**
//    * @Author: PanBin
//    * @Description: 释放锁
//    * @CreateDate: 2018-9-21 15:02
//    * @Param []
//    * @Return void
//    */
//    public synchronized void unlock() {
//        if (locked) {
//            redisTemplate.delete(lockKey);
//            locked = false;
//        }
//    }
//
//    /**=============================common============================*/
//    /**
//     * @Author: PanBin
//     * @Description: 指定缓存失效时间
//     * @CreateDate: 2018-9-20 16:29
//     * @Param [key, time]
//     * @Return boolean
//     */
//    public boolean expire(String key,long time){
//        try {
//            if(time>0){
//                redisTemplate.expire(key, time, TimeUnit.SECONDS);
//            }
//            return true;
//        } catch (Exception e) {
//            e.printStackTrace();
//            return false;
//        }
//    }
//
//    /**
//     * @Author: PanBin
//     * @Description: 根据key 获取过期时间
//     * @CreateDate: 2018-9-20 16:29
//     * @Param [key]
//     * @Return long
//     */
//    public long getExpire(String key){
//        return redisTemplate.getExpire(key,TimeUnit.SECONDS);
//    }
//
//    /**
//     * @Author: PanBin
//     * @Description: 判断key是否存在
//     * @CreateDate: 2018-9-20 16:30
//     * @Param [key]
//     * @Return boolean: true 存在 false不存在
//     */
//    public boolean hasKey(String key){
//        try {
//            return redisTemplate.hasKey(key);
//        } catch (Exception e) {
//            e.printStackTrace();
//            return false;
//        }
//    }
//
//    /**
//     * @Author: PanBin
//     * @Description: 删除缓存
//     * @CreateDate: 2018-9-20 16:30
//     * @Param [key: 可以传一个值 或多个]
//     * @Return void
//     */
//    public void del(String ... key){
//        if(key!=null&&key.length>0){
//            if(key.length==1){
//                redisTemplate.delete(key[0]);
//            }else{
//                redisTemplate.delete(CollectionUtils.arrayToList(key));
//            }
//        }
//    }
//
//    /**=============================String============================*/
//
//    /**
//     * @Author: PanBin
//     * @Description: 普通缓存获取
//     * @CreateDate: 2018-9-20 16:31
//     * @Param [key]
//     * @Return java.lang.Object
//     */
//    public Object get(String key) {
//        return key == null ? null : redisTemplate.opsForValue().get(key);
//    }
//
//    /**
//     * @Author: PanBin
//     * @Description: 普通缓存放入
//     * @CreateDate: 2018-9-20 16:32
//     * @Param [key 键, value 值]
//     * @Return boolean
//     */
//    public boolean set(String key,Object value) {
//        try {
//            redisTemplate.opsForValue().set(key, value);
//            return true;
//        } catch (Exception e) {
//            e.printStackTrace();
//            return false;
//        }
//    }
//
//    /**
//     * @Author: PanBin
//     * @Description: 普通缓存放入并设置时间
//     * @CreateDate: 2018-9-20 16:32
//     * @Param [key 键, value 值, time 时间(秒) time要大于0 如果time小于等于0 将设置无限期]
//     * @Return boolean
//     */
//    public boolean set(String key,Object value,long time){
//        try {
//            if(time>0){
//                redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
//            }else{
//                set(key, value);
//            }
//            return true;
//        } catch (Exception e) {
//            e.printStackTrace();
//            return false;
//        }
//    }
//
//    /**
//     * @Author: PanBin
//     * @Description: 递增
//     * @CreateDate: 2018-9-20 16:33
//     * @Param [key 键, delta 要增加几(大于0)]
//     * @Return long
//     */
//    public long increase(String key, long delta){
//        if(delta<0){
//            throw new RuntimeException("递增因子必须大于0");
//        }
//        return redisTemplate.opsForValue().increment(key, delta);
//    }
//
//    /**
//     * 递减
//     * @param key
//     * @param by
//     * @return
//     */
//    /**
//     * @Author: PanBin
//     * @Description:
//     * @CreateDate: 2018-9-20 16:35
//     * @Param [key 键, delta 要减少几(小于0)]
//     * @Return long
//     */
//    public long decrease(String key, long delta){
//        if(delta<0){
//            throw new RuntimeException("递减因子必须大于0");
//        }
//        return redisTemplate.opsForValue().increment(key, -delta);
//    }
//
//    /**================================Map=================================*/
//    /**
//     * @Author: PanBin
//     * @Description: 获取键，项对应的值
//     * @CreateDate: 2018-9-20 16:37
//     * @Param [key 键 不能为null, item 项 不能为null]
//     * @Return java.lang.Object
//     */
//    public Object hGet(String key,String item){
//        return redisTemplate.opsForHash().get(key, item);
//    }
//
//    /**
//     * @Author: PanBin
//     * @Description: 获取hashKey对应的所有键值
//     * @CreateDate: 2018-9-20 16:38
//     * @Param [key 对应的多个键值]
//     * @Return java.util.Map<java.lang.Object,java.lang.Object>
//     */
//    public Map<Object,Object> hmGet(String key){
//        return redisTemplate.opsForHash().entries(key);
//    }
//
//    /**
//     * @Author: PanBin
//     * @Description:
//     * @CreateDate: 2018-9-20 16:40
//     * @Param [key 键, map 对应多个键值]
//     * @Return boolean
//     */
//    public boolean hmSet(String key, Map<String,Object> map){
//        try {
//            redisTemplate.opsForHash().putAll(key, map);
//            return true;
//        } catch (Exception e) {
//            e.printStackTrace();
//            return false;
//        }
//    }
//
//    /**
//     * @Author: PanBin
//     * @Description: 设置map值,并设置时间
//     * @CreateDate: 2018-9-20 16:40
//     * @Param [key 键, map 对应多个键值, time 时间(秒)]
//     * @Return boolean
//     */
//    public boolean hmSet(String key, Map<String,Object> map, long time){
//        try {
//            redisTemplate.opsForHash().putAll(key, map);
//            if(time>0){
//                expire(key, time);
//            }
//            return true;
//        } catch (Exception e) {
//            e.printStackTrace();
//            return false;
//        }
//    }
//
//    /**
//     * @Author: PanBin
//     * @Description: 向一张hash表中放入数据,如果不存在将创建
//     * @CreateDate: 2018-9-20 16:41
//     * @Param [key 键, item 项, value 值]
//     * @Return boolean
//     */
//    public boolean hSet(String key,String item,Object value) {
//        try {
//            redisTemplate.opsForHash().put(key, item, value);
//            return true;
//        } catch (Exception e) {
//            e.printStackTrace();
//            return false;
//        }
//    }
//
//    /**
//     * @Author: PanBin
//     * @Description: 向一张hash表中放入数据,如果不存在将创建,并设置时间
//     * @CreateDate: 2018-9-20 16:42
//     * @Param [key 项, item 项, value 值, time 时间(秒)，注意:如果已存在的hash表有时间,这里将会替换原有的时间]
//     * @Return boolean
//     */
//    public boolean hSet(String key ,String item,Object value,long time) {
//        try {
//            redisTemplate.opsForHash().put(key, item, value);
//            if(time>0){
//                expire(key, time);
//            }
//            return true;
//        } catch (Exception e) {
//            e.printStackTrace();
//            return false;
//        }
//    }
//
//    /**
//     * @Author: PanBin
//     * @Description: 删除hash表中的值
//     * @CreateDate: 2018-9-20 16:43
//     * @Param [key 键,不能为null, item 项,可以使多个,不能为null]
//     * @Return void
//     */
//    public void hDel(String key, Object... item){
//        redisTemplate.opsForHash().delete(key,item);
//    }
//
//    /**
//     * @Author: PanBin
//     * @Description: 判断hash表中是否有该项的值
//     * @CreateDate: 2018-9-20 16:45
//     * @Param [key 键,不能为null, item 项,不能为null]
//     * @Return boolean
//     */
//    public boolean hHasKey(String key, String item){
//        return redisTemplate.opsForHash().hasKey(key, item);
//    }
//
//    /**
//     * @Author: PanBin
//     * @Description: hash递增 如果不存在,就会创建一个 并把新增后的值返回
//     * @CreateDate: 2018-9-20 16:45
//     * @Param [key 键, item 项, by 要增加几(大于0)]
//     * @Return double
//     */
//    public double hIncrease(String key, String item,double by){
//        return redisTemplate.opsForHash().increment(key, item, by);
//    }
//
//    /**
//     * @Author: PanBin
//     * @Description: hash递减
//     * @CreateDate: 2018-9-20 16:46
//     * @Param [key 键, item 项, by 要减少记(小于0)]
//     * @Return double
//     */
//    public double hDecrease(String key, String item,double by){
//        return redisTemplate.opsForHash().increment(key, item,-by);
//    }
//
//    /**============================set=============================*/
//    /**
//     * @Author: PanBin
//     * @Description: 根据key获取Set中的所有值
//     * @CreateDate: 2018-9-20 16:47
//     * @Param [key 键]
//     * @Return java.util.Set<java.lang.Object>
//     */
//    public Set<Object> sGet(String key){
//        try {
//            return redisTemplate.opsForSet().members(key);
//        } catch (Exception e) {
//            e.printStackTrace();
//            return null;
//        }
//    }
//
//    /**
//     * @Author: PanBin
//     * @Description: 根据value从一个set中查询,是否存在
//     * @CreateDate: 2018-9-20 16:48
//     * @Param [key 键, value 值]
//     * @Return boolean
//     */
//    public boolean sHasKey(String key,Object value){
//        try {
//            return redisTemplate.opsForSet().isMember(key, value);
//        } catch (Exception e) {
//            e.printStackTrace();
//            return false;
//        }
//    }
//
//    /**
//     * @Author: PanBin
//     * @Description: 将数据放入set缓存
//     * @CreateDate: 2018-9-20 16:49
//     * @Param [key 键, values 值,可以是多个]
//     * @Return long 成功个数
//     */
//    public long sSet(String key, Object...values) {
//        try {
//            return redisTemplate.opsForSet().add(key, values);
//        } catch (Exception e) {
//            e.printStackTrace();
//            return 0;
//        }
//    }
//
//    /**
//     * @Author: PanBin
//     * @Description: 将set数据放入缓存,并设置时间
//     * @CreateDate: 2018-9-20 16:50
//     * @Param [key 键, time 时间(秒), values 值,可以是多个]
//     * @Return long 成功个数
//     */
//    public long sSetAndTime(String key,long time,Object...values) {
//        try {
//            Long count = redisTemplate.opsForSet().add(key, values);
//            if(time>0) expire(key, time);
//            return count;
//        } catch (Exception e) {
//            e.printStackTrace();
//            return 0;
//        }
//    }
//
//    /**
//     * @Author: PanBin
//     * @Description: 获取set缓存的长度
//     * @CreateDate: 2018-9-20 16:51
//     * @Param [key 键]
//     * @Return long
//     */
//    public long sGetSetSize(String key){
//        try {
//            return redisTemplate.opsForSet().size(key);
//        } catch (Exception e) {
//            e.printStackTrace();
//            return 0;
//        }
//    }
//
//    /**
//     * @Author: PanBin
//     * @Description: 移除值为value的set
//     * @CreateDate: 2018-9-20 16:51
//     * @Param [key 键, values 值,可以是多个]
//     * @Return long  移除的个数
//     */
//    public long setRemove(String key, Object ...values) {
//        try {
//            Long count = redisTemplate.opsForSet().remove(key, values);
//            return count;
//        } catch (Exception e) {
//            e.printStackTrace();
//            return 0;
//        }
//    }
//
//    /**===============================list=================================*/
//
//    /**
//     * @Author: PanBin
//     * @Description: 获取list缓存的内容
//     * @CreateDate: 2018-9-20 16:53
//     * @Param [key 键, start 开始, end 结束,0到-1代表所有值]
//     * @Return java.util.List<java.lang.Object>
//     */
//    public List<Object> lGet(String key, long start, long end){
//        try {
//            return redisTemplate.opsForList().range(key, start, end);
//        } catch (Exception e) {
//            e.printStackTrace();
//            return null;
//        }
//    }
//
//    /**
//     * @Author: PanBin
//     * @Description: 获取list缓存的长度
//     * @CreateDate: 2018-9-20 16:54
//     * @Param [key]
//     * @Return long
//     */
//    public long lGetListSize(String key){
//        try {
//            return redisTemplate.opsForList().size(key);
//        } catch (Exception e) {
//            e.printStackTrace();
//            return 0;
//        }
//    }
//
//    /**
//     * @Author: PanBin
//     * @Description: 通过索引获取list中的值
//     * @CreateDate: 2018-9-20 16:54
//     * @Param [key 键, index 索引,index>=0时,0:表头,1:第二个元素，依次类推；index<0时，-1，表尾，-2倒数第二个元素，依次类推]
//     * @Return java.lang.Object
//     */
//    public Object lGetIndex(String key,long index){
//        try {
//            return redisTemplate.opsForList().index(key, index);
//        } catch (Exception e) {
//            e.printStackTrace();
//            return null;
//        }
//    }
//
//    /**
//     * @Author: PanBin
//     * @Description: 将list放入缓存
//     * @CreateDate: 2018-9-20 16:56
//     * @Param [key 键, value 值]
//     * @Return boolean
//     */
//    public boolean lSet(String key, Object value) {
//        try {
//            redisTemplate.opsForList().rightPush(key, value);
//            return true;
//        } catch (Exception e) {
//            e.printStackTrace();
//            return false;
//        }
//    }
//
//    /**
//     * @Author: PanBin
//     * @Description: 将list放入缓存,并设置时间
//     * @CreateDate: 2018-9-20 16:57
//     * @Param [key 键, value 值, time 时间(秒)]
//     * @Return boolean
//     */
//    public boolean lSet(String key, Object value, long time) {
//        try {
//            redisTemplate.opsForList().rightPush(key, value);
//            if (time > 0) expire(key, time);
//            return true;
//        } catch (Exception e) {
//            e.printStackTrace();
//            return false;
//        }
//    }
//
//    /**
//     * @Author: PanBin
//     * @Description: 将list放入缓存
//     * @CreateDate: 2018-9-20 16:57
//     * @Param [key 键, value 值]
//     * @Return boolean
//     */
//    public boolean lSet(String key, List<Object> value) {
//        try {
//            redisTemplate.opsForList().rightPushAll(key, value);
//            return true;
//        } catch (Exception e) {
//            e.printStackTrace();
//            return false;
//        }
//    }
//
//    /**
//     * @Author: PanBin
//     * @Description: 将list放入缓存,并设置过期时间
//     * @CreateDate: 2018-9-20 16:58
//     * @Param [key 键, value 值, time 时间(秒)]
//     * @Return boolean
//     */
//    public boolean lSet(String key, List<Object> value, long time) {
//        try {
//            redisTemplate.opsForList().rightPushAll(key, value);
//            if (time > 0) expire(key, time);
//            return true;
//        } catch (Exception e) {
//            e.printStackTrace();
//            return false;
//        }
//    }
//
//    /**
//     * @Author: PanBin
//     * @Description: 根据索引修改list中的某条数据
//     * @CreateDate: 2018-9-20 16:58
//     * @Param [key 键, index 索引, value 值]
//     * @Return boolean
//     */
//    public boolean lUpdateIndex(String key, long index,Object value) {
//        try {
//            redisTemplate.opsForList().set(key, index, value);
//            return true;
//        } catch (Exception e) {
//            e.printStackTrace();
//            return false;
//        }
//    }
//
//    /**
//     * @Author: PanBin
//     * @Description: 移除N个值为value
//     * @CreateDate: 2018-9-20 16:59
//     * @Param [key 键, count 移除多少个, value 值]
//     * @Return long 移除的个数
//     */
//    public long lRemove(String key,long count,Object value) {
//        try {
//            Long remove = redisTemplate.opsForList().remove(key, count, value);
//            return remove;
//        } catch (Exception e) {
//            e.printStackTrace();
//            return 0;
//        }
//    }
//}
